//
//  tdl/mem/bitmap.h
//  Created by tommy on 13/03/11
//

#ifndef tdl_mem_bitmap_h
#define tdl_mem_bitmap_h

#include "tdlexcept.h"
using namespace tdl;

namespace tdl {
//////////////////////
class bitmap
{
	enum { byte_size = 8 };
protected:
	char*		m_pmem;
	size_t		m_mem_size;

public:
	static size_t calc_size(uint32_t bit_num)
	{ return bit_num / byte_size + 1; }

	bitmap() : m_pmem(NULL), m_mem_size(0)
	{ }

	~bitmap()
	{ }

	// if you want all bits are 1, @c should be 0xFF
	void initialize(char *pmem, size_t mem_size, uint8_t c = 0) throw(bitmap_ex)
	{
		if(pmem == NULL || mem_size == 0)
			THROW(bitmap_ex, "bitmap::initialize() error: illegal input parameter");

		m_mem_size = mem_size;
		m_pmem = pmem;

		::memset(m_pmem, c, m_mem_size);
	}

	void attach(char *pmem, size_t mem_size) throw(bitmap_ex)
	{
		if(pmem == NULL || mem_size == 0)
			THROW(bitmap_ex, "bitmap::initialize() error: illegal input parameter");

		m_mem_size = mem_size;
		m_pmem = pmem;
	}

	// if you want all bits are 1, @c should be 0xFF
	void reset(uint8_t c = 0)
	{ ::memset(m_pmem, c, m_mem_size); }

	void set1(uint32_t val) throw(bitmap_ex)
	{
		if(val >= m_mem_size * byte_size)
			THROW(bitmap_ex, "bitmap::set1() error: too big val");

		uint32_t nbyte = val / byte_size;
		uint32_t nbit = val % byte_size;

		m_pmem[nbyte] |= (1 << nbit);
	}

	void set0(uint32_t val) throw(bitmap_ex)
	{
		if(val >= m_mem_size * byte_size)
			THROW(bitmap_ex, "bitmap::set0() error: too big val");

		uint32_t nbyte = val / byte_size;
		uint32_t nbit = val % byte_size;

		m_pmem[nbyte] &= ~(1 << nbit);
	}

	uint8_t get(uint32_t val) throw(bitmap_ex)
	{
		if(val >= m_mem_size * byte_size)
			THROW(bitmap_ex, "bitmap::set0() error: too big val");

		uint32_t nbyte = val / byte_size;
		uint32_t nbit = val % byte_size;
		uint8_t mask = (1 << nbit);

		return (m_pmem[nbyte] & mask) >> nbit;
	}

	bool is1(uint32_t val) throw(bitmap_ex)
	{ return get(val) > 0; }

	bool is0(uint32_t val) throw(bitmap_ex)
	{ return get(val) == 0; }

	char* get_ptr() const
	{ return m_pmem; }

	size_t get_size() const
	{ return m_mem_size; }
};

////////////////////
}	// end of namespace
#endif

